/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package app.net.server;

import app.game.GlobalStatics;
import app.net.Client;
import app.net.messages.SimpleStringMessage;
import app.net.messages.SyncMessage;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * get data from loop and sent to client
 *
 * @author skyr
 */
public class ServerSyncThread implements Runnable {

    private boolean running = true;
    private ServerGameLoop serverGameLoop;
    private HashMap<Integer, ObjectOutputStream> streams;

    public ServerSyncThread(ServerGameLoop serverGameLoop) {
        this.serverGameLoop = serverGameLoop;
        streams = new HashMap<Integer, ObjectOutputStream>();
    }

    public void setOutputStream(Integer id, ObjectOutputStream oos) {
        streams.put(id, oos);
    }

    @Override
    public void run() {
        while (running) {
            if (!serverGameLoop.getSendReset()) {// if match is over and needs reset
                SimpleStringMessage simpleStringMessage = new SimpleStringMessage("reset");
                try {
                    for (Iterator<Client> cIt = serverGameLoop.getClientsList().iterator(); cIt.hasNext();) {
                        Client client = cIt.next();
                        ObjectOutputStream oos = streams.get(client.getId());
                        oos.writeObject(simpleStringMessage);
                    }
                    serverGameLoop.setSendReset(true);
                } catch (IOException ex) {
                    Logger.getLogger(ServerSyncThread.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            // for each client(spectator or player) and for each entity
            for (Iterator<Client> cIt = serverGameLoop.getClientsList().iterator(); cIt.hasNext();) {
                Client client = cIt.next();
                ObjectOutputStream oos = streams.get(client.getId());

                try {
                    for (Iterator<Client> pIt = serverGameLoop.getPlayers().iterator(); pIt.hasNext();) {
                        Client player = pIt.next();
                        /*
                         * build sync message and send
                         */
                        SyncMessage sm = new SyncMessage();
                        sm.setId(player.getId());
                        sm.setX(player.getFighterEntity().getX());
                        sm.setY(player.getFighterEntity().getY());
                        sm.setIsAtk(player.getFighterEntity().getIsAtk());
                        sm.setIsDef(player.getFighterEntity().getIsDef());
                        sm.setIsRight(player.isIsRight());
                        sm.setHealth(player.getFighterEntity().getHealthPoints());
                        try {
                            oos.writeObject(sm);
                        } catch (SocketException ex) {
                            serverGameLoop.removeClient(player);
                        } catch (IOException ex) {
                            Logger.getLogger(ServerSyncThread.class.getName()).log(Level.SEVERE, "write message fail", ex);
                        }
                    }
                } catch (Exception e) {
                    System.err.println("Message not sent " + e.getMessage() + " continuing...");
                }

            }
            try {
                Thread.sleep(GlobalStatics.syncTick);
            } catch (InterruptedException ex) {
            }
        }
    }

    public void start() {
        Thread t = new Thread(this);
        t.start();
    }

    public void stop() {
        running = false;
        for (Iterator<ObjectOutputStream> it = streams.values().iterator(); it.hasNext();) {
            ObjectOutputStream objectOutputStream = it.next();
            try {
                objectOutputStream.close();
            } catch (IOException ex) {
                Logger.getLogger(ServerSyncThread.class.getName()).log(Level.SEVERE, "stream close fail", ex);
            }
        }
    }
}
